import { AbsoluteLayout } from "@/js/components/Layout"
import { GraphNode } from "../../GraphNode"
import { SearchMenu } from "../../SearchMenu"
import { BoxSelectionHelp } from "../../BoxSelectionHelp/src"
import { KeyHelper } from "@/utils/KeyHelper"
import ParserError from "@/js/GraphParser/src/ParserError"

export class GraphView extends AbsoluteLayout{
    list: GraphNode[] = []

    searchMenu = new SearchMenu()
    boxSelectionHelp?: BoxSelectionHelp

    graphNodeClass : {[k:string]: object } = {
        GraphNode: GraphNode
    }

    key: KeyHelper

    constructor(w = "100%", h = "100%"){
        super()
        this.setStyle({
            "background":`linear-gradient(0deg,#444 0px,#444 1px,transparent 1px,transparent 100px),linear-gradient(90deg,#444 0px,#444 1px,transparent 1px,transparent 100px);`,
            "background-size": "40px 40px",
            "background-position": "0 0,15px 15px",
            "overflow":"hidden",
            "background-color":"#333",
            "width": w,
            "height": h,
            "position":"absolute",
            transition: "transform 0.3s ease",
            "user-select": 'none'
        })

        this.setAttribute("tabindex", '0')

        this.$el.setAttribute("style", this.toStyleString())

        document.addEventListener('contextmenu', function(e) {
            e.preventDefault()
        })
        
        this.init()
        this.key = new KeyHelper(this.$el)
        this.boxSelectionHelp = new BoxSelectionHelp(this)
    }

    init(){
        this.searchMenu.show(-10000, -10000, -10000, -10000)
        this.addEventListener("mousedown", ({button, clientX, clientY, offsetX, offsetY, target}:MouseEvent)=>{
            if(button === 2 && target === this.$el){
                setTimeout(()=>{
                    this.searchMenu.show(offsetX, offsetY, clientX, clientY)
                })
            }
        })
    }

    /**
     * 添加节点模板类
     * @param graphNodeClass 
     * @param name 
     */
    addGraphNodeClass<T extends typeof GraphNode>(graphNodeClass: T, name?: string){
        this.graphNodeClass[name || graphNodeClass.name] = graphNodeClass
    }

    /**
     * 添加子节点
     * @param graphNode 
     */
    add(graphNode: GraphNode){
        this.appendChild(graphNode)
        this.list.push(graphNode)
    }

    /**
     * 移除子节点
     * @param graphNode 
     */
    remove(graphNode: GraphNode){
        this.removeChild(graphNode)
        this.list.splice(this.list.indexOf(graphNode), 1)
    }

    /**
     * 导入
     * @param project 
     */
    import(project: any[]){
        const graphNodes: {[k:string]: GraphNode} = {}
        project.forEach(item=>{
            const Class = this.graphNodeClass[item.ClassName] as typeof GraphNode
            if(Class){
                const graphNode = new Class()
                graphNode.attach(this)
                graphNode.import(item)
                graphNodes[item.uuid] = graphNode

                setTimeout(()=>{
                    Object.keys(item.outputs).forEach(k=>{
                        item.outputs[k].forEach((info:any)=>{
                            graphNode.outputs[k].createLinkNodeLine(  graphNodes[info.uuid], info.name )
                        })
                    })
                    graphNode.importSuccess(item)
                })
            }
            else{
                console.warn(`不存在图形节点：${item.ClassName}`)
            }
        })
    }

    /**
     * 导出
     * @returns 
     */
    export(){
        return this.list.map(graphNode=>graphNode.export())
    }

    /**
     * 使用插件
     * @param obj 
     */
    use(obj: any){
        if(obj.modules instanceof Array){
            obj.modules.forEach((item: any)=>{
                const group = this.searchMenu.createGroup(item.groupName)
                if(item.expand === false) group.userData.showBody(false)
                else if(item.expand) group.userData.showBody(true)
                Object.keys(item.nodes).forEach(k=>{
                    
                    this.addGraphNodeClass(item.nodes[k])
                    const name = (obj.onMenuCreated && obj.onMenuCreated(item.nodes[k], k, obj)) || item.nodes[k].menuName || k

                    group.addItem(name, (x:number, y:number)=>{
                        const objClass = item.nodes[k]
                        let node = new objClass()
        
                        const before = (obj.onNodeCreateBefore && obj.onNodeCreateBefore( node , k, objClass, obj))
                        node = typeof before  === 'undefined' ? objClass : node
        
                        if(node){
                            node.attach(this).position("absolute", x + 'px' , y + 'px')
                            obj.onNodeCreateAfter && obj.onNodeCreateAfter(node)
                        }
        
                        this.searchMenu.close()
                    })
                })
            })
        }
    }
    
    /**
     * 使用一个错误，显示到节点上
     * @param error 
     */
    useError(error:ParserError){
        if(error instanceof ParserError){
            // 检索错误节点
            for (let i = 0; i < this.list.length; i++) {
                if(this.list[i].uuid === error.uuid){
                    this.list[i].setError(error.message)
                }
            }
        }
    }

    closeError(uuid?:string){
        // 检索错误节点
        for (let i = 0; i < this.list.length; i++) {
            // 如果传入uuid，就查找，不是就全删除
            if(uuid)
            {
                if(this.list[i].uuid === uuid){
                    this.list[i].closeError()
                }
            }
            else this.list[i].closeError()
        }
    }
}